home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / nntpsubr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-31  |  26.8 KB  |  1,180 lines

  1. /*
  2.  *
  3.  * NNTP Server/Client Subroutines - See RFC977
  4.  * Jeffrey R. Comstock. - NR0D - Bloomington, Minnesota USA
  5.  * Copyright 1990 Jeffrey R. Comstock, All Rights Reserved.
  6.  * Permission granted for non-commercial copying and use, provided
  7.  * this notice is retained.
  8.  *
  9.  * DB3FL 9107xx: heavily rewritten and bug fixing in file-handling
  10.  * DB3FL 920121: splitted into several files
  11.  * DG1ZX 9210xx: bug fixing and optimize
  12.  * DG1ZX 9303xx: included POST and XDHR command
  13.  * DG1ZX 930728: included nntp restrictions and history lifetime
  14.  * DG1ZX 941024: fixed bug in xfer_article2() when fullauto = 0 and last
  15.  *               newsgroup specified in the article is not in active file
  16.  */
  17.  
  18. #include <stdio.h>
  19. #include <time.h>
  20. #include <dos.h>
  21. #include <io.h>
  22. #include <dir.h>
  23. #include <ctype.h>
  24. #include <sys/stat.h>
  25.  
  26. #include "global.h"
  27. #include "nntp.h"
  28. #include "files.h"
  29. #include "socket.h"
  30.  
  31.  
  32. int Filecheck = 0;
  33. int16 Nntpquiet = 0;
  34.  
  35. char *Host = NULLCHAR;
  36.  
  37. /* main directory-creating routine
  38.  * handles special chars in pathname - especially for MSDOS
  39.  * returncode: -1 error; 0 success
  40.  */
  41. static int near
  42. make_dir(char *path,int s)
  43. {
  44.     char *cp;
  45.  
  46.     if(path == NULLCHAR)
  47.         return -1;
  48.  
  49.     while((cp = strchr(path,'\\')) != NULLCHAR)
  50.         *cp = '/';
  51.  
  52.     if (access(path,0)) {
  53.         if (mkdir(path)) {
  54.             tprintf("Can't create %s: %s\n",path,sys_errlist[errno]);
  55.             if(s)
  56.                 usprintf(s,fatal,path);
  57.             return -1;
  58.         }
  59.     }
  60.     return 0;
  61. }
  62.  
  63. /* creating path to a new newsgroup
  64.  * handling of "." and "\" in pathnames and length of filename
  65.  * especially MSDOS
  66.  * returncode: -1 error; 0 success */
  67. int make_path(char *group,char w)
  68. {
  69.     FILE *f;
  70.     char cp[LineLen], cp1[LineLen], *cp2;
  71.     int got_it = 0, i, n = 0, len = 0;
  72.  
  73.     if (group == NULLCHAR
  74.         || (f = open_file(Pointer,APPEND_TEXT,0,1)) == NULLFILE)
  75.       return -1;
  76.  
  77.     strcpy(cp1,group);
  78.  
  79.     for(;;) {
  80.       if((cp2 = strchr(cp1,'.')) != NULLCHAR)
  81.         *cp2 = '\0';
  82.       else
  83.         got_it = 1;
  84.  
  85.       sprintf(cp,"%s/%s",News,cp1);
  86.  
  87.       /* make subdir step by step */
  88.       if(make_dir(cp,0)) {
  89.         fclose(f);
  90.         return -1;
  91.       }
  92.  
  93.       if(got_it) {
  94.         if(w) {
  95.           /* now add new newgroup and path to pointer file */
  96.           for (i = 0;cp[i] != NULL;i++) {
  97.             if (cp[i] == '/')
  98.               len = 0;
  99.             /* length limit handling of DOS filename */
  100.             if (len < MAXFILE)
  101.               cp1[n++] = cp[i];
  102.             len ++;
  103.           }
  104.           cp1[n] = '\0';
  105.           fprintf(f,"%s %s\n",group,cp1);
  106.         }
  107.         fclose(f);
  108.         return 0;
  109.       }
  110.       *cp2 = '/';
  111.     }
  112. }
  113.  
  114.  
  115. static int near
  116. update_list(struct nntpsv *a)
  117. {
  118.     FILE *f, *t;
  119.     char *p, *p1, l2[LineLen];
  120.  
  121.     if((f = open_file(Active,READ_TEXT,a->s,0)) == NULLFILE)
  122.         return -1;
  123.  
  124.     if ((t = temp_file(0,1)) == NULLFILE) {
  125.         fclose(f);
  126.         return -1;
  127.     }
  128.     p1 = a->ap->group;
  129.     a->ap->number = 0;                                    /* set highest article number to 0 */
  130.     for (;;) {
  131.         if (fgets(a->buf,LineLen,f) == NULL)
  132.             break;
  133.         a->ap->tmpu = strcspn(a->buf," ");                 /* Length of newsgroup */
  134.         strncpy(l2,a->buf,a->ap->tmpu);                 /* copy newsgroup */
  135.         l2[a->ap->tmpu] = '\0';
  136.         if (strcmp(p1,l2) == 0) {                       /* look for entry */
  137.             p = strchr(a->buf,' ') + 1;
  138.             a->ap->number = (unsigned)atoi(p);            /* get number of messages */
  139.             (a->ap->number)++;                          /* increment number */
  140.             p = strchr(p,' ');
  141.             fprintf(t,"%s %5.5u%s",p1,a->ap->number,p);    /* write back updated newsgroup line */
  142.         } else
  143.             fputs(a->buf,t);                            /* write back existing newsgroup line */
  144.     }
  145.     fclose(f);
  146.     rewind(t);
  147.     if ((f = open_file(Active,WRITE_TEXT,a->s,0)) == NULLFILE) {
  148.         fclose(t);
  149.         return -1;
  150.     }
  151.     for(;;) {                            /* copy temp. file to active file */
  152.         if (fgets(a->buf,LineLen,t) == NULL)
  153.             break;
  154.         fputs(a->buf,f);
  155.     }
  156.     fclose(t);
  157.     /* highest article in active file = 0 and update allowed ? */
  158.     if ((a->ap->number == 0) && fullauto) {
  159.         /* create new subdirectories and add new group to active file */
  160.         make_path(a->ap->group,1);
  161.         a->ap->number = 1;
  162.         fprintf(f,"%s 00001 00001 y\n",a->ap->group);
  163.     }
  164.     fclose(f);
  165.     return (a->ap->number);
  166. }
  167.  
  168. /* main file-checking routine
  169.  * returncode: -1 if error; 0 success */
  170. static int near
  171. check_file(char *path)
  172. {
  173.     if(path == NULLCHAR)
  174.         return -1;
  175.     if(access(path,0))
  176.         return close(creat(path,S_IWRITE));
  177.     return 0;
  178. }
  179.  
  180. /* checkes if path to given article exists
  181.  * returncode: -1 error; 1 success; 0 no path */
  182. int
  183. get_path2(struct article *art)
  184. {
  185.     FILE *f;
  186.     char line[LineLen], *p;
  187.  
  188.     if(art->group == NULLCHAR
  189.       || (f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
  190.         return -1;
  191.  
  192.     p = art->group;
  193.     art->path = NULLCHAR;
  194.  
  195.     for (;;) {
  196.         if (fgets(line,LineLen,f) == NULL)
  197.             break;
  198.         if (strcspn(line," ") != strlen(p))
  199.             continue;
  200.         if (strnicmp(p,line,strlen(p)) == 0) {
  201.             p = (strchr(line,' ')) + 1;
  202.             if(art->path != NULLCHAR)
  203.                 xfree(art->path);
  204.             art->path = strxdup(p);
  205.             rip2(art->path);
  206.             fclose(f);
  207.             return 1;
  208.         }
  209.     }
  210.     fclose(f);
  211.     return 0;
  212. }
  213.  
  214. /* returncode: -1 error; 0 success */
  215. static int near
  216. dup_f(FILE *in,FILE *out,struct nntpsv *mp)
  217. /* Path: bug in col 1 of article body bug fixed by G4JEC 901019....*/
  218. /* Path-field no more expected in line 1 (DG1ZX) */
  219. {
  220.   char *p;
  221.   int blank_line_flag = 1;
  222.  
  223.   for(;;) {
  224.     if (fgets(mp->buf,LineLen,in) == NULL)
  225.       return 0;
  226.  
  227.     if (blank_line_flag)
  228.       if (strnicmp(mp->buf,pth,5) == 0) {
  229.     p = strchr(mp->buf,' \t') + 1;
  230.     fprintf(out,"%s%s!%s",pth,Host,p);
  231.     blank_line_flag = 0;
  232.     continue;
  233.       }
  234.     /* oh oh - nntpserv is modifying articles....*/
  235.     if (strlen(mp->buf) == 1 && mp->buf[0] == '.')
  236.       continue;
  237.     fputs(mp->buf,out);
  238.   }
  239. }
  240. /*
  241.    copy article to \spool\news\junk and update history and fwd.seq file
  242.    returncode: < 1 if error; 1 success
  243. */
  244. static int near
  245. dofwd(struct nntpsv *mp,FILE *f,FILE *history,char *part1)
  246. {
  247.     FILE *fwd;
  248.  
  249.     if(mp == NULLNNTPSV)
  250.         return -1;
  251.  
  252.     sprintf(mp->buf,"%s/fwd.seq",News);
  253.     if ((fwd = open_file(mp->buf,"r+",mp->s,0)) == NULLFILE)
  254.         return -1;
  255.  
  256.     fgets(mp->buf,LineLen,fwd);
  257.     mp->hold_i = atoi(mp->buf) + 1;
  258.     fprintf(history,"%s JUNK/%u\n",part1,mp->hold_i);
  259.     rewind(fwd);
  260.     fprintf(fwd,"%u",mp->hold_i);
  261.     fclose(fwd);
  262.  
  263.     sprintf(mp->buf,"%s/%u",Forward,mp->hold_i);
  264.     if ((fwd = open_file(mp->buf,WRITE_TEXT,mp->s,0)) == NULLFILE)
  265.         return -2;
  266.  
  267.     rewind(f);
  268.     dup_f(f,fwd,mp);
  269.     fclose(fwd);
  270.     return 1;
  271. }
  272.  
  273. /* checks the file-system used for NNTP
  274.  * returncode: -1 if error; 0 success - and "Filecheck" is set to 1 */
  275. int
  276. check_system(void)
  277. {
  278.     FILE *f;
  279.     char line[LineLen], *cp, *cp1;
  280.     int error = 0;
  281.  
  282.     if (Host == NULLCHAR) {
  283.         cp = strxdup(Hostname);
  284.         if((cp1 = strchr(cp,'.')) != NULLCHAR)
  285.             *cp1 = '\0';
  286.         Host = strxdup(cp);
  287.         xfree(cp);
  288.     }
  289.  
  290.     if(Filecheck)
  291.         return 0;
  292.  
  293.     error  = make_dir(Forward,0);
  294.     error |= check_file(Pointer);
  295.     error |= check_file(History);
  296.     error |= check_file(Active);
  297.     error |= check_file(Poll);
  298.  
  299.     if(error)
  300.         goto quit;
  301.  
  302.     sprintf(line,"%s/fwd.seq",News);
  303.     if (access(line,0)) {
  304.         if((f = open_file(line,"w+",0,1)) == NULLFILE) {
  305.             goto quit;
  306.         }
  307.         fputs("1\n",f);
  308.         fclose(f);
  309.     }
  310.     sprintf(line,"%s/sequence.seq",Mailqdir);
  311.     if (access(line,0)) {
  312.         if((f = open_file(line,"w+",0,1)) == NULLFILE) {
  313.             goto quit;
  314.         }
  315.         fputs("1\n",f);
  316.         fclose(f);
  317.     }
  318.     Filecheck = 1;
  319.     return 0;
  320.  
  321. quit:
  322.     Filecheck = 0;
  323.     tputs("Error in NNTP file system\n");
  324.     return -1;
  325. }
  326.  
  327. void
  328. rip2(char *s)
  329. {
  330.     char *cp;
  331.  
  332.     if((cp = strpbrk(s,"\r\n")) != NULLCHAR)
  333.         *cp = '\0';
  334. }
  335.  
  336. /* file-receiving routine
  337.  * returncode: -1 if error or 'recvline' faults; 0 success; 1 if blank line */
  338. int
  339. recv_file(FILE *fp,int s)
  340. {
  341.     char line[LineLen];
  342.     int check = 0;
  343.  
  344.     for (;;) {
  345.         if (recvline(s,line,LineLen) == -1)
  346.             return -1;
  347.         rip2(line);
  348.  
  349.         if(strcmp(line,".") == 0)
  350.             return 0;
  351.  
  352.         if(!check) {                    /* only enabled on first line! */
  353.             check = 1;
  354.             if (*line == '\0')          /* check for blank line */
  355.                 return 1;
  356.         }
  357.         fprintf(fp,"%s\n",line);
  358.     }
  359. }
  360.  
  361. /* checks incoming article-id against existing articles
  362.  * returncode: -1 if error; 1 if article exists; 0 no article found */
  363. int
  364. check_article(char *id)
  365. {
  366.     char *p, line[LineLen];
  367.     FILE *f;
  368.  
  369.     if(id == NULLCHAR || (p = strchr(id,'<')) == NULLCHAR
  370.       || (f = open_file(History,READ_TEXT,0,1)) == NULLFILE)
  371.         return -1;
  372.  
  373.     for(;;) {
  374.         if (fgets(line,LineLen,f) == NULL) {
  375.             fclose(f);
  376.             return 0;
  377.         }
  378.         if (strstr(line,p) != NULL) {
  379.             fclose(f);
  380.             return 1;
  381.         }
  382.     }
  383. }
  384.  
  385. #ifdef NNTPLIFETIME
  386. /***************************************************************/
  387. /*                                    */
  388. /*  Parse a line for date and time in Arpanet format           */
  389. /*  (Day, day Month year hh:mm:ss Zone) and return unixtime.   */
  390. /*  Interpret date/time always as local time, except we found  */
  391. /*  GMT or UT(C) in header field                   */
  392. /*                                    */
  393. /*  return =  0  ==> error                       */
  394. /*        <> 0     ==> unixtime (GMT)                   */
  395. /*                                    */
  396. /***************************************************************/
  397.  
  398. time_t
  399. articletime(char *line)
  400. {
  401.      char buf[13], *cp = line;
  402.      int i, day, year;
  403.      time_t unixtime;
  404.      struct date *datest;
  405.      struct time *timest;
  406.  
  407.      /* skip initial blanks and optional day-of-week */
  408.      while(!isdigit(*cp))
  409.        ++cp;
  410.  
  411.      /* test minimum length */
  412.      if( (*cp == '\0') || (strlen(cp) < 14) )
  413.        return (time_t)0;
  414.  
  415.      /* get day */
  416.      day = atoi(cp);
  417.  
  418.      /* get month */
  419.      cp = strpbrk(cp," ") + 1;
  420.      for(i=0; i < 12; ++i)
  421.         if(strnicmp(Months[i],cp,3) == 0)
  422.             break;
  423.      if(i == 12)
  424.         return (time_t)0;
  425.  
  426.      /* get year (some newsreader uses year with century) */
  427.      if ( (cp = strpbrk(cp," ")) == NULLCHAR)
  428.         return (time_t)0;
  429.      year = atoi(++cp);
  430.      if (year > 99)
  431.        year %= 100;
  432.      cp = strpbrk(cp," ") + 1;
  433.  
  434.      sprintf(buf,"%02d%02d%02d %02d%02d%02d", year, i + 1, day, atoi(cp),
  435.             atoi(cp + 3),  *(cp + 5) == ':' ? atoi(cp + 6) : 0 );
  436.  
  437.      datest = (struct date *)mxallocw(sizeof(struct date));
  438.      timest = (struct time *)mxallocw(sizeof(struct time));
  439.      unixtime = make_nntime(datest,timest,buf);
  440.      xfree(timest);
  441.      xfree(datest);
  442.  
  443.      /* error in make_nntime() ? */
  444.      if(!unixtime)
  445.         return (time_t)0;
  446.  
  447.      /* if timezone is not GMT, interpretation as local time. So add */
  448.      /* timeoffset to get GMT */
  449.      if ( (strstr(cp,"GMT") == NULLCHAR) && (strstr(cp,"UT") == NULLCHAR) )
  450.        unixtime+=timezone;
  451.  
  452.      return unixtime;
  453. }
  454. #endif
  455.  
  456. int
  457. xfer_article2(FILE *f,struct nntpsv *mp)
  458. {
  459.     char line[LineLen], *p, *p1, *group = NULLCHAR, *from = NULLCHAR;
  460.     char his[LineLen], l[LineLen];
  461. #ifdef NNTPLIFETIME
  462.     char *date_time = NULLCHAR;
  463. #endif
  464.     FILE *fptr, *history;
  465.     struct tm *stm;
  466.     int x;
  467. #ifdef CONTROL
  468.     int control = 0;
  469. #endif
  470.  
  471.     if(f == NULLFILE || mp == NULLNNTPSV ||
  472.       (history = open_file(History,APPEND_TEXT,mp->s,0)) == NULLFILE) {
  473.         xfree(mp->id);
  474.         return -1;
  475.     }
  476.     if((mp->ap = (struct article *)mxallocw(sizeof(struct article))) == NULLARTICLE) {
  477.         xfree(mp->id);
  478.         fclose(history);
  479.         return -1;
  480.     }
  481.  
  482.     for (;;) {
  483.         if (fgets(line,LineLen,f) == NULL)
  484.             break;
  485.         rip2(line);
  486.         if(*line == '\0')
  487.             break;
  488.  
  489.         /* FROM: line */
  490.         if (strnicmp(line,frm,6) == 0) {
  491.             p = strchr(line,' ') + 1;
  492.             from = strxdup(p);
  493.             continue;
  494.         }
  495.  
  496.         /* NEWSGROUPS: line */
  497.         if (strnicmp(line,ngrps,12) == 0) {
  498.             p = strchr(line,' ') + 1;
  499.             group = strxdup(p);
  500.             continue;
  501.         }
  502.  
  503. #ifdef NNTPLIFETIME
  504.         /* DATE: line */
  505.         if (strnicmp(line,ndate,6) == 0) {
  506.             p = strchr(line,' ') + 1;
  507.             date_time = strxdup(p);
  508.             continue;
  509.         }
  510. #endif
  511.     }
  512.     stm = gmtime(&currtime);
  513.     sprintf(his,"%s %2.2d%2.2d%2.2d %2.2d%2.2d%2.2d",
  514.         mp->id,
  515.         stm->tm_year,stm->tm_mon+1,stm->tm_mday,
  516.         stm->tm_hour,stm->tm_min,stm->tm_sec);
  517.  
  518.     mp->hold_i = 0;
  519.     p = group;
  520.     x = 1;
  521. #ifdef NNTPLIFETIME
  522.     if ( articletime(date_time) < (currtime+timezone-lifetime*DAYS) )
  523.       x = 0;
  524.     if(date_time != NULLCHAR)
  525.       xfree(date_time);
  526. #endif
  527.     while (x) {
  528.       if ((p1 = strchr(p,',')) != NULLCHAR) {
  529.         p1 = line;            /* get next newsgroup */
  530.         while (*p != ',')
  531.           *(p1++) = *(p++);
  532.         *p1 = '\0';
  533.         p++;
  534.         mp->ap->group = strxdup(line);
  535.       } else {
  536.         mp->ap->group = strxdup(p); /* get last newsgroup */
  537.         x = 0;
  538.       }
  539.  
  540.       update_list(mp);
  541.       if (mp->ap->number > 0) {
  542.         get_path2(mp->ap);
  543.         mp->hold_i = 1;
  544.         sprintf(line,"%s/%u",mp->ap->path,mp->ap->number);
  545.         rewind(f);
  546.         if ((fptr = open_file(line,WRITE_TEXT,mp->s,0)) == NULLFILE) {
  547.           fclose(history);
  548.           xfree(mp->ap->group);
  549.           goto quit;
  550.         }
  551.         dup_f(f,fptr,mp);
  552.         fclose(fptr);
  553.  
  554.         /* build line for history file step by step */
  555.         sprintf(l," %s/%u",mp->ap->group,mp->ap->number);
  556.         strcat(his,l);
  557.  
  558. #ifdef CONTROL
  559.         if (strcmp(mp->ap->group,"control") == 0)
  560.           control = 1;
  561. #endif
  562.         if(mp->ap->path != NULLCHAR)
  563.           xfree(mp->ap->path);
  564.       }
  565.       xfree(mp->ap->group);
  566.     }
  567.  
  568.     if (mp->hold_i == 0) {
  569.       if ((x = dofwd(mp,f,history,his)) < 1)
  570.         mp->hold_i = 0;
  571.         /* newsgroup did not exist in active file, so forward it to junk */
  572.         xfree(group);
  573.         group = strxdup("JUNK");
  574.     } else {
  575.       /* update history file */
  576.       fprintf(history,"%s\n",his);
  577.     }
  578.  
  579.     fclose(history);
  580.     if(Nntpquiet < 2)
  581.       tprintf("New mail in newsgroup %s\n  from <%s> at %s%s",
  582.            group,from,ctime(&currtime),!Nntpquiet ? "\007" : "");
  583.     if(Nntpquiet == 3)
  584.       log(mp->s,"NNTP new mail <%s>",group);
  585.  
  586. #ifdef CONTROL
  587.     if (control == 1)
  588.       docontrol(f,mp);
  589. #endif
  590. quit:
  591.     xfree(mp->id);
  592.     xfree(mp->ap);
  593.     if(from != NULLCHAR)
  594.       xfree(from);
  595.     if(group != NULLCHAR)
  596.       xfree(group);
  597.     return 0;
  598. }
  599.  
  600. /* checks for not valid chars in a line
  601.  * returncode: 0 if valid; 1 if invalid */
  602. int
  603. check_blank(char *bp)
  604. {
  605.     if (strpbrk(bp,"!@#$%^&*()_+=<>,./?~`[]{}\|0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") == NULL)
  606.         return 1;
  607.     return 0;
  608. }
  609.  
  610. /* converts timestring to unix-compatible structure
  611.  * returncode: 0 (!!) if error; > 0 success */
  612. static int32
  613. make_nntime(struct date *d,struct time *t,char *str)
  614. {
  615.     char *cp, tmp[3];
  616.  
  617.     if(str == NULLCHAR)
  618.         return 0L;
  619.  
  620.     tmp[2] = '\0';
  621.     cp = str;
  622.  
  623.     strncpy(tmp,cp,2);
  624.  
  625.     d->da_year = atoi(tmp)+1900;
  626.  
  627.     if (d->da_year < 1980)
  628.         d->da_year = 1980;
  629.  
  630.     if (d->da_year > 2099)
  631.         goto quit;
  632.  
  633.     cp+=2;
  634.  
  635.     strncpy(tmp,cp,2);
  636.     d->da_mon = atoi(tmp);
  637.     if (d->da_mon < 1 || d->da_mon > 12)
  638.         goto quit;
  639.  
  640.     cp+=2;
  641.  
  642.     strncpy(tmp,cp,2);
  643.     d->da_day = atoi(tmp);
  644.     if (d->da_day < 1 || d->da_day > 32)
  645.         goto quit;
  646.  
  647.     cp+=3;
  648.  
  649.     strncpy(tmp,cp,2);
  650.     t->ti_hour = atoi(tmp);
  651.     if (/* t->ti_hour < 0 || */ t->ti_hour > 24)
  652.         goto quit;
  653.  
  654.     cp+=2;
  655.  
  656.     strncpy(tmp,cp,2);
  657.     t->ti_min = atoi(tmp);
  658.     if (/* t->ti_min < 0 || */ t->ti_min > 60)
  659.         goto quit;
  660.  
  661.     cp+=2;
  662.  
  663.     strncpy(tmp,cp,2);
  664.     t->ti_sec = atoi(tmp);
  665.     if (/* t->ti_sec < 0 || */ t->ti_sec > 60)
  666.         goto quit;
  667.  
  668.     t->ti_hund = 0;
  669.     return (dostounix(d,t));
  670. quit :
  671.     return 0L;
  672. }
  673.  
  674. /* checks if two spaces exists in given string
  675.  * returncode: -1 if error; 1 success */
  676. static int near
  677. check_one(char *str)
  678. {
  679.     char *cp;
  680.  
  681.     if(str == NULLCHAR || (cp = strchr(str,' ')) == NULLCHAR)
  682.         return -1;
  683.  
  684.     if (strchr(++cp,' ') == NULLCHAR)
  685.         return -1;
  686.  
  687.     return 1;
  688. }
  689.  
  690. static int
  691. restreql(char *w, char *s)
  692. {
  693.     while (*s && *w) {
  694.         switch (*w) {
  695.             case '*':
  696.                 for (w++; *s; s++)
  697.                     if (restreql(w, s))
  698.                         return 1;
  699.                 break;
  700.             default:
  701.                 if (*w != *s)
  702.                     return 0;
  703.                 w++, s++;
  704.                 break;
  705.         }
  706.     }
  707.     if (*s)
  708.         return 0;
  709.     while (*w)
  710.         if (*w++ != '*')
  711.             return 0;
  712.  
  713.     return 1;
  714. }
  715.  
  716. /* return code 0 = no matches, 1 = match */
  717. static int near
  718. ngmatcha(int (*func)(char *,char *),int dflt,struct g_list *ngspec, struct g_list *matchlist)
  719. {
  720.     int match = dflt;
  721.     char *cp;
  722.     struct g_list *n, *m = matchlist;
  723.  
  724.     for(;;) {
  725.         if ((cp = strchr(m->str,'/')) != NULLCHAR)
  726.             *cp = '\0';
  727.         n = ngspec;
  728.         for (;;) {
  729.             if (n->str[0] == '!') {      /* Handle negation */
  730.                 if ((*func)(n->str+1, m->str)) {
  731.                     match = 0;
  732.                 }
  733.             } else {
  734.                 if ((*func)(n->str, m->str)) {
  735.                     match = 1;
  736.                 }
  737.             }
  738.             if (n->next == NULLG)
  739.                 break;
  740.             else
  741.                 n = n->next;
  742.         }
  743.         if (m->next == NULLG)
  744.             break;
  745.         else
  746.             m = m->next;
  747.     }
  748.     return (match);
  749. }
  750.  
  751.  
  752. #if (defined(NNTPRESTRICT) || defined(NNTPLIFETIME))
  753. /*
  754.    checks if article is newer than date/time specified in string
  755.    and if the groups in the given string matches with the
  756.    newsgroups in historyfile.
  757.    If new news exist, MID from all articles are copied in temporary file
  758.    returncode:    -3 if poll time/date is to old
  759.         -2 if request with "*" received
  760.         -1 if error
  761.          0 if no new news
  762.          1 if new news available
  763. */
  764.  
  765. int
  766. newnews(char *string,struct nntpsv *mp,FILE *f, char serv_cli)
  767. {
  768.     char line[LineLen], *cp1, groups[LineLen], *cp = string;
  769.     struct g_list *ng, *hist, *ngp, *histp, *ptr;
  770.     FILE *f1;
  771.     int match, j, i = 1, error = -1;
  772.  
  773.     if (check_one(string) == -1)
  774.         return -1;
  775.  
  776.     /* cut off newsgroups from time/date */
  777.     while (*(cp++) > 32)
  778.         i++;
  779.     if (strlen(cp) < 13)
  780.         return -1;
  781.     strncpy(groups,string,i-1);
  782.     groups[i-1] = '\0';
  783.  
  784. #ifdef NNTPRESTRICT
  785. #ifdef undef
  786.     /*
  787.         if desired, don't support request with a single "*" in the poll string.
  788.      */
  789.     if(serv_cli && restrict) {                        /* subroutine from server ? */
  790.       for (cp1 = groups; *cp1 != NULL; cp1++) {
  791.         if (*cp1 == '*') {                             /* oops i've got you  */
  792.           while (*(++cp1) == '*');                     /* skip all "*" */
  793.           if ( (*cp1 == ',') || (*cp1 == NULL))      /* End or "," is following ? */
  794.             return -2;                                 /* send error message */
  795.         }
  796.         if ( (cp1 = strpbrk(cp1,",")) == NULLCHAR)    /* set pointer to next group */
  797.           break;
  798.       }
  799.     }
  800. #endif /* undef */
  801.     /*
  802.        if desired, don't support request with any leading "*"
  803.        e.g. *, *.*, *.*.*. You always have to specify top level group !
  804.     */
  805.     if(serv_cli && restrict) {
  806.       for (cp1 = groups; *cp1 != NULL; cp1++) {
  807.         if (*cp1 == '*') {                          /* oops i've got you  */
  808.           while (*(++cp1) == '*');                    /* skip all "*" */
  809.           if (!isalnum(*cp1))                        /* ".", "," or NULL is following ? */
  810.             return -2;                                /* send error message */
  811.         }
  812.         if ((cp1 = strpbrk(cp1,",")) == NULLCHAR)    /* set pointer to next group */
  813.           break;
  814.       }
  815.     }
  816. #endif
  817.  
  818.     /* convert date/time string in unixtime format */
  819.     mp->datest = (struct date *)mxallocw(sizeof(struct date));
  820.     mp->timest = (struct time *)mxallocw(sizeof(struct time));
  821.     if ((mp->unixtime = make_nntime(mp->datest,mp->timest,cp)) < 1)
  822.         goto quit;
  823.  
  824. #ifdef NNTPLIFETIME
  825.     if (serv_cli && (mp->unixtime < (currtime+timezone-(time_t)lifetime*DAYS)))
  826.         return -3;
  827. #endif
  828.  
  829.     /* build list of all newsgroups in the given string */
  830.     ng = ngp = (struct g_list *)mxallocw(sizeof(struct g_list));
  831.     cp = groups;
  832.  
  833.     for (;;) {
  834.         if (strchr(cp,',') == NULLCHAR ) {
  835.             ng->str = strxdup(cp);
  836.             ng->next = NULLG;
  837.             break;
  838.         }
  839.         j = strcspn(cp,",");
  840.         ng->str = (char *)mxallocw(j+1);
  841.         strncpy(ng->str,cp,j);
  842.         ng->str[j] = '\0';
  843.         ng->next = (struct g_list *)mxallocw(sizeof(struct g_list));
  844.         ng = ng->next;
  845.         if((cp1 = strchr(cp,',')) != NULLCHAR)
  846.             cp = cp1 + 1;
  847.         else
  848.             break;
  849.     }
  850.  
  851.    /* now compare date/time and newsgroups with all entries in history file */
  852.  
  853.    if ((f1 = open_file(History,READ_TEXT,0,1)) == NULLFILE)
  854.        goto quit1;
  855.  
  856.    error = 0;
  857.    for (;;) {
  858.        if (fgets(line,LineLen,f1) == NULL)
  859.            break;
  860.        rip2(line);
  861.        pwait(NULL);
  862.  
  863.        if ((mp->ftime = make_nntime(mp->datest,mp->timest,strchr(line,' ') + 1)) == 0)
  864.            break;   /* something wrong with this line so stop searching */
  865.  
  866.        /* article is older than date/time in given string.
  867.           ==> read next line from history */
  868.        if ((mp->ftime - mp->unixtime) < 0)
  869.            continue;
  870.  
  871.          /* if article is newer then check if newsgroups in given string
  872.             and entry in history matches */
  873.  
  874.          for(i = 3, cp = line; i; --i)
  875.              cp = strchr(cp,' ') + 1;
  876.          histp = (struct g_list *)mxallocw(sizeof(struct g_list));
  877.          hist = histp;
  878.  
  879.          /* build list of all newsgroups from the article */
  880.          for (;;) {
  881.              if (strchr(cp,' ') == NULLCHAR) {
  882.                  hist->str = strxdup(cp);
  883.                  hist->next = NULLG;
  884.                  break;
  885.              }
  886.              j = strcspn(cp," ");
  887.              hist->str = (char *)mxallocw(j+1);
  888.              strncpy(hist->str,cp,j);
  889.              hist->str[j] = '\0';
  890.              hist->next = (struct g_list *)mxallocw(sizeof(struct g_list));
  891.              hist = hist->next;
  892.              if((cp1 = strchr(cp,' ')) != NULLCHAR)
  893.                  cp = cp1 + 1;
  894.              else
  895.                  break;
  896.          }
  897.  
  898.          /* now check if both list matches */
  899.          match = ngmatcha(restreql,0,ngp,histp);
  900.  
  901.          /* free list of all newsgroups specified in the article */
  902.          ptr = histp;
  903.          for (;;) {
  904.              ptr = histp->next;
  905.              xfree(histp->str);
  906.              xfree(histp);
  907.              histp = ptr;
  908.              if (histp == NULLG)
  909.                  break;
  910.          }
  911.          /* if no matches exists then read new line from history */
  912.          if (!match)
  913.              continue;
  914.  
  915.          /* we found a new news, so copy message id to file
  916.             and read next line from history    */
  917.  
  918.          error = 1;
  919.          cp = line;
  920.          while ( *cp > 32 )
  921.              fputc(*(cp++),f);
  922.          fputc('\n',f);
  923.  
  924.      }
  925.  
  926.      fclose(f1);
  927.  
  928.      /* free list of all newsgroups specified in the given string */
  929. quit1:
  930.      ptr = ngp;
  931.      for (;;) {
  932.          ptr = ngp->next;
  933.          xfree(ngp->str);
  934.          xfree(ngp);
  935.          ngp = ptr;
  936.          if (ngp == NULLG)
  937.              break;
  938.      }
  939. quit:
  940.      rewind(f);
  941.      xfree(mp->datest);
  942.      xfree(mp->timest);
  943.  
  944.      return error;
  945. }
  946.  
  947. #else
  948.  
  949. /*
  950.     checks if article is newer than date/time specified in string
  951.     and if the groups in the given string matches with the
  952.     newsgroups in historyfile.
  953.     If new news exist, MID from all articles are copied in temporary file
  954.     returncode: -1 if error; 0 if no new news; 1 new news available
  955. */
  956.  
  957. int
  958. newnews(char *string,struct nntpsv *mp,FILE *f)
  959. {
  960.     char *cp1, line[LineLen], groups[LineLen], *cp = string;
  961.     struct g_list *ng, *hist, *ngp, *histp, *ptr;
  962.     FILE *f1;
  963.     int match, j, all = 1, i = 1, error = -1;
  964.  
  965.     if (check_one(string) == -1)
  966.         return -1;
  967.  
  968.     /* cut off newsgroups from time/date */
  969.     while (*(cp++) > 32)
  970.         i++;
  971.     if (strlen(cp) < 13)
  972.         return -1;
  973.     strncpy(groups,string,i-1);
  974.     groups[i-1] = '\0';
  975.  
  976.     if(strcmp(groups,"*") != 0)
  977.         all = 0;
  978.  
  979.     /* convert date/time string in unixtime format */
  980.     mp->datest = (struct date *)mxallocw(sizeof(struct date));
  981.     mp->timest = (struct time *)mxallocw(sizeof(struct time));
  982.     if ((mp->unixtime = make_nntime(mp->datest,mp->timest,cp)) < 1)
  983.         goto quit;
  984.  
  985.     /* build list of all newsgroups in the given string */
  986.     if (!all) {
  987.         ng = ngp = (struct g_list *)mxallocw(sizeof(struct g_list));
  988.         cp = groups;
  989.  
  990.         for (;;) {
  991.             if (strchr(cp,',') == NULLCHAR ) {
  992.                 ng->str = strxdup(cp);
  993.                 ng->next = NULLG;
  994.                 break;
  995.             }
  996.             j = strcspn(cp,",");
  997.             ng->str = (char *)mxallocw(j+1);
  998.             strncpy(ng->str,cp,j);
  999.             ng->str[j] = '\0';
  1000.             ng->next = (struct g_list *)mxallocw(sizeof(struct g_list));
  1001.             ng = ng->next;
  1002.             if((cp1 = strchr(cp,',')) != NULLCHAR)
  1003.                 cp = cp1 + 1;
  1004.             else
  1005.                 break;
  1006.         }
  1007.     }
  1008.  
  1009.      /* now compare date/time and newsgroups with all entries in history file */
  1010.  
  1011.     if ((f1 = open_file(History,READ_TEXT,0,1)) == NULLFILE)
  1012.         goto quit1;
  1013.  
  1014.     error = 0;
  1015.     for (;;) {
  1016.         if (fgets(line,LineLen,f1) == NULL)
  1017.             break;
  1018.         rip2(line);
  1019.  
  1020.         if ((mp->ftime = make_nntime(mp->datest,mp->timest,strchr(line,' ') + 1)) == 0)
  1021.             break;   /* something wrong with this line so stop searching */
  1022.  
  1023.         /* article is older than date/time in given string.
  1024.              ==> read next line from history */
  1025.         if ((mp->ftime - mp->unixtime) < 0)
  1026.             continue;
  1027.  
  1028.         /* if article is newer then check if newsgroups in given string
  1029.              and entry in history matches */
  1030.  
  1031.         if (!all) {
  1032.             for(i = 3, cp = line; i; --i)
  1033.                 cp = strchr(cp,' ') + 1;
  1034.             histp = (struct g_list *)mxallocw(sizeof(struct g_list));
  1035.             hist = histp;
  1036.  
  1037.             /* build list of all newsgroups from the article */
  1038.             for (;;) {
  1039.                 if (strchr(cp,' ') == NULLCHAR) {
  1040.                     hist->str = strxdup(cp);
  1041.                     hist->next = NULLG;
  1042.                     break;
  1043.                 }
  1044.                 j = strcspn(cp," ");
  1045.                 hist->str = (char *)mxallocw(j+1);
  1046.                 strncpy(hist->str,cp,j);
  1047.                 hist->str[j] = '\0';
  1048.                 hist->next = (struct g_list *)mxallocw(sizeof(struct g_list));
  1049.                 hist = hist->next;
  1050.                 if((cp1 = strchr(cp,' ')) != NULLCHAR)
  1051.                     cp = cp1 + 1;
  1052.                 else
  1053.                     break;
  1054.             }
  1055.  
  1056.             /* now check if both list matches */
  1057.             match = ngmatcha(restreql,0,ngp,histp);
  1058.  
  1059.             /* free list of all newsgroups specified in the article */
  1060.             ptr = histp;
  1061.             for (;;) {
  1062.                 ptr = histp->next;
  1063.                 xfree(histp->str);
  1064.                 xfree(histp);
  1065.                 histp = ptr;
  1066.                 if (histp == NULLG)
  1067.                     break;
  1068.             }
  1069.             /* if no matches exists then read new line from history */
  1070.             if (!match)
  1071.                 continue;
  1072.         }
  1073.  
  1074.         /* we found a new news, so copy message id to file
  1075.              and read next line from history    */
  1076.  
  1077.         error = 1;
  1078.         cp = line;
  1079.         while ( *cp > 32 )
  1080.             fputc(*(cp++),f);
  1081.         fputc('\n',f);
  1082.  
  1083.     }
  1084.  
  1085.     fclose(f1);
  1086.  
  1087.     /* free list of all newsgroups specified in the given string */
  1088. quit1:
  1089.     if (!all) {
  1090.         ptr = ngp;
  1091.         for (;;) {
  1092.             ptr = ngp->next;
  1093.             xfree(ngp->str);
  1094.             xfree(ngp);
  1095.             ngp = ptr;
  1096.             if (ngp == NULLG)
  1097.                 break;
  1098.         }
  1099.     }
  1100. quit:
  1101.     rewind(f);
  1102.     xfree(mp->datest);
  1103.     xfree(mp->timest);
  1104.  
  1105.     return error;
  1106. }
  1107. #endif
  1108.  
  1109. /*
  1110.  * checks for a minimum header:
  1111.  * The minimum requirement for an incoming article is that it must have
  1112.  * a newsgroups: line, a message-id: line, a date: line, a from: line,
  1113.  * a subject: line and a blank line to delimit header from body.
  1114.  *
  1115.  * returncode: 0 complete; 1 not complete
  1116.  *
  1117.  */
  1118. int
  1119. garbled(FILE *f)
  1120. {
  1121.     char line[LineLen];
  1122.     int ok = 0;
  1123.  
  1124.     rewind(f);
  1125.     for(;;) {
  1126.         if (fgets(line,LineLen,f) == NULL)
  1127.             break;
  1128.         if (strnicmp(line,ngrps,12) == 0)
  1129.             ok |= 1;
  1130.         if (strnicmp(line,msgid,12) == 0)
  1131.             ok |= 2;
  1132.         if (strnicmp(line,ndate,6) == 0)
  1133.             ok |= 4;
  1134.         if (strnicmp(line,frm,6) == 0)
  1135.             ok |= 8;
  1136.         if (strnicmp(line,subj,9) == 0)
  1137.             ok |= 16;
  1138.         if (check_blank(line))
  1139.             break;
  1140.     }
  1141.     rewind(f);
  1142.     return (ok == 31) ? 0 : 1;
  1143. }
  1144.  
  1145. /**************************************************************************/
  1146. /*  checks id from IHAVE offer against existing articles id received by   */
  1147. /*  newnews command. When this test passed, checks if one of the hostname */
  1148. /*  in pathfield is identical with hostname, we are polling now. (dg1zx)  */
  1149. /*                                        */
  1150. /*  return-code: 0 = no such article          ==> IHAVE ok           */
  1151. /*          1 = article already exists  ==> don't offer           */
  1152. /*                                        */
  1153. /**************************************************************************/
  1154.  
  1155. int
  1156. check_ihave (FILE *fp, char *id,struct nntpsv *mp, char *hostn)
  1157. {
  1158.     char *p = strchr(id,'<'), *mid, line[LineLen];
  1159.     int ret;
  1160.  
  1161.   /* checks if article is offered in this session from host */
  1162.   rewind(fp);
  1163.   for (;;) {
  1164.     if (fgets(line,LineLen,fp) == NULL)
  1165.       break;
  1166.     if (strstr(line,p) != NULL)
  1167.       return 1;
  1168.   }
  1169.   if(hostn == NULLCHAR)
  1170.     return 0;
  1171.  
  1172.   /* now we check the pathfield of this article */
  1173.   mid = strxdup(id);
  1174.   p = strchr(mid,'>')+1;
  1175.   *p = '\0';            /* cut off CR LF ! */
  1176.   ret = doarticle(mid,mp,0,hostn);
  1177.   xfree(mid);
  1178.   return ((ret==1) ? 0 : 1);
  1179. }
  1180.